package com.ytf.dogbox.inteflyCamera;


import android.annotation.SuppressLint;

import com.ytf.dogbox.util.Log;

import java.util.ArrayList;


/**
 * Author ： BlackHao
 * Time : 2017/12/5 14:32
 * Description : 读取 H264文件送入解码器解码线程
 */

public class MediaCodecThread extends Thread {

    private String TAG=MediaCodecThread.class.getSimpleName();

    //解码器
    private MediaCodecUtil util;
    //文件路径
    private String path;
    //文件读取完成标识
    private boolean isFinish = false;
    //这个值用于找到第一个帧头后，继续寻找第二个帧头，如果解码失败可以尝试缩小这个值
    private static final int FRAME_MIN_LEN = 20;
    //一般H264帧大小不超过200k,如果解码失败可以尝试增大这个值
    private static final int FRAME_MAX_LEN = 300 * 1024;
    //根据帧率获取的解码每帧需要休眠的时间,根据实际帧率进行操作
    private static final int PRE_FRAME_TIME = 1000 / 25;
    //按帧用来缓存h264数据
    private ArrayList<byte[]> frameList = new ArrayList<>();
    //缓存最多的帧数 减少缓存帧数看下是否能减少内存溢出
    private int MAX_FRAME_SIZE = 15;


    private DecodeThread decodeThread=null;

    /**
     * 初始化解码器 这个不是从文件路径获取h264
     *
     * @param util 解码 Util
     */
    public MediaCodecThread(MediaCodecUtil util) {
        this.util = util;
//        frameList = new ArrayList<>();
        frameList.clear();
//        //开启解码线程
//        decodeThread=new DecodeThread();
//        decodeThread.start();
    }

    /**
     * 初始化解码器
     *
     * @param util 解码 Util
     * @param path 文件路径
     */
    public MediaCodecThread(MediaCodecUtil util, String path) {
        this.util = util;
        this.path = path;
//        frameList = new ArrayList<>();
        frameList.clear();
        //开启解码线程
        decodeThread=new DecodeThread();
        decodeThread.start();
    }

    public void setUtil(MediaCodecUtil util){
        this.util=util;
    }

    public void addH264(byte[] h264){
        try {
            if (h264.length>0){
                addFrame(h264);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 寻找指定 buffer 中 h264 头的开始位置
     *
     * @param data   数据
     * @param offset 偏移量
     * @param max    需要检测的最大值
     * @return h264头的开始位置 ,-1表示未发现
     */
    private int findHead(byte[] data, int offset, int max) {
        int i;
        for (i = offset; i <= max; i++) {
            //发现帧头
            if (isHead(data, i))
                break;
        }
        //检测到最大值，未发现帧头
        if (i == max) {
            i = -1;
        }
        return i;
    }

    /**
     * 判断是否是I帧/P帧头:
     * 00 00 00 01 65    (I帧)
     * 00 00 00 01 61 / 41   (P帧)
     * 00 00 00 01 67    (SPS)
     * 00 00 00 01 68    (PPS)
     *
     * @param data   解码数据
     * @param offset 偏移量
     * @return 是否是帧头
     */
    private boolean isHead(byte[] data, int offset) {
        boolean result = false;
        // 00 00 00 01 x
        if (data[offset] == 0x00 && data[offset + 1] == 0x00
                && data[offset + 2] == 0x00 && data[3] == 0x01 && isVideoFrameHeadType(data[offset + 4])) {
            result = true;
        }
        // 00 00 01 x
        if (data[offset] == 0x00 && data[offset + 1] == 0x00
                && data[offset + 2] == 0x01 && isVideoFrameHeadType(data[offset + 3])) {
            result = true;
        }
        return result;
    }

    /**
     * I帧或者P帧
     */
    private boolean isVideoFrameHeadType(byte head) {
        return head == (byte) 0x65 || head == (byte) 0x61 || head == (byte) 0x41
                || head == (byte) 0x67 || head == (byte) 0x68;
    }

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //开启解码线程
        decodeThread=new DecodeThread();
        decodeThread.start();
    }

    //视频解码
    @SuppressLint("NewApi")
    private void onFrame(byte[] frame, int offset, int length) {
        if (frame.length>0){
            if (util != null && frame.length>0) {
                try {
//                    long s = System.currentTimeMillis();
                    boolean flag=util.onFrame(frame, offset, length);
                    if (!flag){
                        frame=null;
//                        System.gc();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("TAG", "mediaCodecUtil is NULL");
            }
        }

    }

    //修眠
    private void sleepThread(long startTime, long endTime) {
        //根据读文件和解码耗时，计算需要休眠的时间
        long time = PRE_FRAME_TIME - (endTime - startTime);
//        Log.e("tiwolf", "sleepThread: 解码-流 start时间"+startTime+";endtime时间"+endTime );
        if (time > 0) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //将视频数据添加到缓存List
    private void addFrame(byte[] frame) throws InterruptedException {
//        Log.e("tiwolf", "addFrame: 添加帧图片" );
//        frameList.add(frame);
//        //当长度多于MAX_FRAME_SIZE时,休眠2秒，避免OOM
//        if (frameList.size() > MAX_FRAME_SIZE) {
//            Thread.sleep(2000);
//        }
//        Log.e("tiwolf", "addFrame: 解码-流当前列表的值为"+frameList.size());
        //设置如下
        //当frameList里面的尺寸小于100的时候，才添加。否则就不添加
        if (frameList.size()<MAX_FRAME_SIZE){
//            Log.i(TAG, "addFrame: 帧数据添加");
            frameList.add(frame);
        } else{
            Log.i(TAG, "addFrame: 帧数据太多了，需要gc");
            frame=null;
//            System.gc();
        }
        if (decodeThread==null){
//            Log.e("tiwolf", "addFrame: 解码-流 当前解码器已经无法使用，另外重启生成解码器" );
        }

//        //当长度多于MAX_FRAME_SIZE时,休眠2秒，避免OOM
//        if (frameList.size() > MAX_FRAME_SIZE) {
//            Thread.sleep(2000);
//        }
    }

    //手动终止读取文件，结束线程
    public void stopThread() {
        isFinish = true;
    }

    public void setMaxFrameNum(int num){
        MAX_FRAME_SIZE=num;
    }

    /**
     * 解码线程
     */
    private class DecodeThread extends Thread {
        @Override
        public void run() {
            super.run();
            Log.e("tiwolf", "run: 解码线程="+currentThread().getName() );
            long start;
            while (!isFinish || frameList.size() > 0) {
                start = System.currentTimeMillis();
                if (frameList != null && frameList.size() > 0 && frameList.get(0)!=null && frameList.get(0).length>0) {
//                    Log.e("tiwolf", "run: 解码-流画帧图片");
                    onFrame(frameList.get(0), 0, frameList.get(0).length);
                    //移除已经解码的数据
                    frameList.remove(0);
//                    Log.e("tiwolf", "run: 解码-流移除已经画了的帧");
                    //休眠
//                    sleepThread(start, System.currentTimeMillis());
                }else if (frameList != null && frameList.size() >0 && (frameList.get(0)==null || frameList.get(0).length==0)){
                    //如果出现某项为空或者是它的包长度为0的时候，说明这个有问题，不经过解码直接清除掉
                    frameList.remove(0);
                }
//                Log.e("tiwolf", "run: 解码-流-一帧需要的时间"+(System.currentTimeMillis()-start) );

                //休眠
                sleepThread(start, System.currentTimeMillis());
            }
        }
    }

}
